/**
 * videoRealComp和videosRealComp整合参数区分的指令
 * 用于绑定元素的拖动和缩放行为。
 *
 * 此指令主要用于处理视频组件的拖动和缩放功能。它通过监听鼠标和触摸事件来实现组件的动态位置和大小调整。
 * 具体功能包括：
 * 1. 判断是否允许拖动或缩放。
 * 2. 处理全屏模式下的拖动限制。
 * 3. 调整组件的样式以禁止默认的拖动行为。
 * 4. 实现拖动和缩放的逻辑。
 *
 * @param {HTMLElement} el - 绑定指令的元素。
 * @param {Object} binding - 绑定的指令对象，包含flag、parentClassName和that等属性。
 * @param {Object} vNode - 虚拟节点，用于Vue的内部操作。
 */
export default {
  bind(el, binding) {
    // 获取指令中定义的标志位和父类名
    const flag = binding.value?.flag;
    const parentClassName = binding.value?.parentClassName;
    const _this = binding.value.that;

    /* 拖动开始 */
    el.onmousedown = (e) => {
      // 根据flag判断是否执行拖动逻辑
      if (flag) {
        // 如果已经在全屏模式下，则不执行拖动
        if (_this.isScreenFull) {
          return false;
        }
        // 处理分屏视频的层级问题
        // 处理分屏视频层级问题
        handleSplitScreenVideoLayers(_this);

        // 如果视频设置为不可拖动，则返回
        if (_this.dragVideo === true) {
          return;
        }

        // 禁止iframe的拖动事件
        divSetStyle(_this, "iframId", "pointerEvents", "none");

        // 阻止事件冒泡
        e.stopPropagation();

        // 如果元素类名中包含no-drag，则不执行拖动
        if (el._prevClass.indexOf("no-drag") !== -1) {
          return false;
        }
        // 切换视频项的类
        toggleVideoItemClass(el);
      }

      // 获取父元素并设置其宽度和高度为100%
      let parentElement = el.closest(`.${parentClassName}`);
      if (parentElement) {
        parentElement.style.width = "100%";
        parentElement.style.height = "100%";
      }

      // 根据flag判断是执行拖动还是缩放逻辑
      if (flag) {
        if (el._prevClass.indexOf("stop-drag") === -1) {
          handleDrag(el, e, binding);
        } else {
          // 缩放
          move(el, e, binding);
        }
        _this.setTopZIndex();
      } else {
        handleDrag(el, e, binding);
      }
    };

    /* 触摸开始 */
    el.ontouchstart = (e) => {
      let parentElement = el.closest(`.${parentClassName}`);
      if (parentElement) {
        parentElement.style.width = "100%";
        parentElement.style.height = "100%";
      }
      e.stopPropagation();

      // 获取初始触摸位置
      let event = e || window.event;
      const currentX = event.changedTouches[0].clientX;
      const currentY = event.changedTouches[0].clientY;

      // 获取元素的计算样式
      const computedStyle = document.defaultView.getComputedStyle(el, null);
      let computedStyleLeft, computedStyleTop;

      // 根据样式计算元素的初始位置（百分比或像素）
      if (computedStyle.left.includes("%")) {
        computedStyleLeft =
          +document.body.clientWidth *
          (+computedStyle.left.replace(/%/g, "") / 100);
        computedStyleTop =
          +document.body.clientHeight *
          (+computedStyle.top.replace(/%/g, "") / 100);
      } else {
        computedStyleLeft = +computedStyle.left.replace("px", "");
        computedStyleTop = +computedStyle.top.replace("px", "");
      }

      // 触摸移动事件处理函数
      document.ontouchmove = function (touchmoveEvent) {
        // 根据条件判断是否允许拖动
        if (
          el._prevClass.indexOf("z-bd") > -1 ||
          el._prevClass.indexOf("canvas-div") > -1 ||
          _this.all?.drag === false
        ) {
          return false;
        }
        if (!flag && el._prevClass.indexOf("dianzi-cs") > -1) {
          return false;
        }

        // 计算元素的新位置
        const dialogElementLeft =
          touchmoveEvent.changedTouches[0].clientX -
          currentX +
          computedStyleLeft;
        const dialogElementTop =
          touchmoveEvent.changedTouches[0].clientY -
          currentY +
          computedStyleTop;

        // 更新元素位置
        el.style.left = dialogElementLeft + "px";
        el.style.top = dialogElementTop + "px";

        // 如果flag为真，调用视频组件工具条的移动函数
        if (flag) {
          _this.$refs.videoCompToolRef?.moveVideoBoxPosition();
        }
      };

      // 触摸结束事件处理函数
      document.ontouchend = () => {
        // 移除移动和结束事件监听器
        document.ontouchmove = null;
        document.ontouchend = null;
        ontouchendFn(flag, el, parentClassName, parentElement, _this);
      };
    };
  },
};

function ontouchendFn(flag, el, parentClassName, parentElement, _this) {
  // 根据flag决定是否重置父元素的样式
  if (flag) {
    el.closest(`.${parentClassName}`)?.removeAttribute("style");
  } else {
    if (parentElement) {
      parentElement.style.width = "0";
      parentElement.style.height = "0";
    }
  }

  // 调整元素的z-index
  _this.setTopZIndex();
}

/**
 * 处理拖动事件的函数
 * @param {HTMLElement} el - 被拖动的元素
 * @param {MouseEvent} event - 鼠标事件
 * @param {Object} binding - 绑定的对象，包含拖动相关的配置
 */
function handleDrag(el, event, binding) {
  // 获取绑定值中的上下文对象
  const _this = binding.value.that;
  // 获取绑定值中的标志位，用于判断是否进行拖动或缩放
  const flag = binding.value?.flag;
  // 获取绑定值中的父类名，用于拖动或缩放时对父元素的样式操作
  const parentClassName = binding.value?.parentClassName;
  // 获取元素的计算样式，用于计算元素的初始位置
  const computedStyle = document.defaultView.getComputedStyle(el, null);
  // 当前鼠标坐标
  // 当前鼠标坐标
  const currentX = event.clientX;
  const currentY = event.clientY;
  // 初始化计算后的左边距和上边距
  let computedStyleLeft, computedStyleTop;
  // 如果计算样式中的left和top是百分比值，转换为像素值
  // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
  if (computedStyle.left.includes("%")) {
    computedStyleLeft =
      +document.body.clientWidth *
      (+computedStyle.left.replace(/%/g, "") / 100);
    computedStyleTop =
      +document.body.clientHeight *
      (+computedStyle.top.replace(/%/g, "") / 100);
  } else {
    computedStyleLeft = +computedStyle.left.replace("px", "");
    computedStyleTop = +computedStyle.top.replace("px", "");
  }
  // 鼠标移动时的处理函数
  document.onmousemove = function (mousemoveEvent) {
    // 如果元素类名包含特定值或配置中禁止拖动，则不执行拖动逻辑
    if (
      el._prevClass.indexOf("z-bd") > -1 ||
      el._prevClass.indexOf("canvas-div") > -1 ||
      _this.all?.drag === false
    ) {
      return false;
    }
    // 如果标志位为false且元素类名包含特定值，则不执行拖动逻辑
    if (!flag && el._prevClass.indexOf("dianzi-cs") > -1) {
      return false;
    }
    // 计算元素的新位置
    const dialogElementLeft =
      mousemoveEvent.clientX - currentX + computedStyleLeft;
    const dialogElementTop =
      mousemoveEvent.clientY - currentY + computedStyleTop;
    // 更新元素位置
    el.style.left = dialogElementLeft + "px";
    el.style.top = dialogElementTop + "px";
    // 如果标志位为true，执行缩放和相关组件的位置更新逻辑
    if (flag) {
      _this.resize();
      //通知工具组件移动位置
      _this.$refs.videoCompToolRef?.moveVideoBoxPosition();
      //通知视图联动移动位置
      _this.$refs.videoToMapRef?.moveVideoBoxPosition();
    }
  };
  // 鼠标松开时的处理函数
  document.onmouseup = () => {
    if (flag) {
      // 恢复iframe的指针事件
      divSetStyle(_this, "iframId", "pointerEvents", "auto");
    }
    let parentElement = el.closest(`.${parentClassName}`);
    document.onmousemove = null;
    document.onmouseup = null;
    ontouchendFn(flag, el, parentClassName, parentElement, _this);
    // 调整顶层元素的z-index
    _this.setTopZIndex();
  };
}

/**
 * 元素移动和缩放处理函数
 * @param {HTMLElement} el - 需要移动和缩放的元素
 * @param {Event} e - 触发事件对象
 * @param {Object} binding - Vue的绑定对象，包含元素的移动和缩放配置
 */
function move(el, e, binding) {
  // 获取绑定值中的上下文对象
  const _this = binding.value.that;
  // 获取元素的父元素
  const parent = el.parentElement;
  // 获取配置中的父元素类名
  const parentClassName = binding.value?.parentClassName;

  // 设置鼠标移动时的处理函数
  document.onmousemove = function (mousemoveEvent) {
    // 阻止事件冒泡和默认行为，以优化移动体验
    // 解决onmouseup事件有时候不触发
    if (el.stopPropagation) {
      el.stopPropagation();
    }
    if (el.preventDefault) {
      el.preventDefault();
    }
    // 获取父元素的计算样式，用于计算元素的相对位置和大小
    const computedStyle = document.defaultView.getComputedStyle(
      el.parentNode,
      null
    );

    // 初始化计算值，用于后续的移动和缩放计算
    // 当前鼠标坐标
    let computedStyleLeft, width, height;
    // 根据计算样式中left的单位是百分比还是像素进行不同的处理
    // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
    if (computedStyle.left.includes("%")) {
      computedStyleLeft =
        +document.body.clientWidth *
        (+computedStyle.left.replace(/%/g, "") / 100);
      width = el.parentNode.style.width.replace(/%/g, "") / 100;
      height = el.parentNode.style.height.replace(/%/g, "") / 100;
    } else {
      computedStyleLeft = +computedStyle.left.replace("px", "");
      width = el.parentNode.style.width.replace("px", "");
      height = el.parentNode.style.height.replace("px", "");
    }

    // 添加移动中的类名，用于视觉反馈
    parent.classList.add("moving");
    // 获取缩放相关的函数和常量
    let transform = _this.myTransform;

    // 计算元素的新宽度和高度
    const dialogElementWidth =
      (mousemoveEvent.clientX - computedStyleLeft) / Number(transform);
    let scale =
      (mousemoveEvent.clientX - computedStyleLeft) / Number(transform) / width;
    let dialogElementHeight = height * scale;

    // 如果存在视频工具栏，确保元素的大小不小于最小值
    // 打开常用功能时，禁止拖拽到小于932px*525px尺寸
    if (
      _this.$refs.videoCompToolRef &&
      _this.$refs.videoCompToolRef.commonTool
    ) {
      if (dialogElementWidth <= _this.commonToolMinWidth) {
        return;
      }
      if (dialogElementHeight <= _this.commonToolMinHeight) {
        return;
      }
    }

    // 根据最小和最大宽度、高度限制，计算元素的最终宽度和高度
    // 放大缩小处理（添加限制范围）
    let vw = Math.min(
      Math.max(dialogElementWidth, _this.dragMinWidth),
      _this.dragMaxWidth
    );
    let vh = Math.min(
      Math.max(dialogElementHeight, _this.dragMinHeight),
      _this.dragMaxHeight
    );
    // 设置元素的新宽度和高度
    el.parentNode.style.width = vw + "px";
    el.parentNode.style.height = vh + "px";

    // 调整元素大小后的回调函数，用于更新状态或样式
    _this.resize();
  };

  // 设置鼠标松开时的处理函数
  document.onmouseup = function () {
    // 如果存在，恢复其鼠标事件处理
    divSetStyle(_this, "iframId", "pointerEvents", "auto");

    // 移除移动中的类名，结束移动和缩放
    parent.classList.remove("moving");
    // 清除鼠标移动和鼠标松开的事件监听器
    document.onmousemove = null;
    document.onmouseup = null;
    // 移除父元素的样式，恢复到默认状态
    el.closest(`.${parentClassName}`)?.removeAttribute("style");
    // 调整元素堆叠顺序的函数，确保当前元素在最顶层
    _this.setTopZIndex();
  };
}

/**
 * 处理分屏视频图层的显示层级。
 * 此函数用于根据当前的index值，调整多个视频对话框的z-index属性，从而控制它们在屏幕上的前后顺序。
 * @param {Object} _this - 包含视频对话框相关信息的对象。
 *   - total: 视频对话框的总数。
 *   - $props.index: 当前活动的视频对话框的索引。
 */
function handleSplitScreenVideoLayers(_this) {
  // 如果视频对话框的数量不为0
  if (_this.total !== 0) {
    // 遍历所有视频对话框
    for (let i = 0; i < _this.total; i++) {
      // 如果当前遍历到的对话框索引与当前活动的索引相同
      let element = document.getElementById("videoDialog" + i);
      if (_this.$props.index === i) {
        // 将该对话框的z-index设置为101，使其位于最前面
        element.style.zIndex = "101";
      } else {
        // 否则，将该对话框的z-index设置为100，使其位于后面
        element.style.zIndex = "100";
      }
    }
  }
}

/**
 * 切换视频项的类
 * 该函数用于在一个视频列表中，点击某个视频项时，切换该项的状态（例如，添加或移除一个表示选中状态的类）。
 * 它首先尝试找到包含该视频项的最近的父元素，
 * 然后在该父元素下移除所有视频项的选中状态（类名'on'）。
 * 接着，它找到包含该视频项的最近的'.video-item'祖先元素，并为该元素添加选中状态。
 * @param {HTMLElement} el - 被点击的视频项元素
 */
function toggleVideoItemClass(el) {
  // 查找最近的 祖先元素
  let bodyAncestor = el.closest(".video-item-body, .video-item-body-c");

  // 如果找到了对应的祖先元素
  if (bodyAncestor) {
    // 获取所有 '.video-item' 子元素（注意：这里假设是直接子元素，如果需要所有后代，则使用 querySelectorAll）
    // 如果需要所有后代中的.video-item，则保持使用 querySelectorAll 不变
    let items = bodyAncestor.querySelectorAll(".video-item");
    // 遍历所有找到的元素并移除 'on' 类
    items.forEach((item) => item.classList.remove("on"));
  }

  // 查找最近的 '.video-item' 祖先元素
  let videoItemAncestor = el.closest(".video-item");

  // 如果找到了对应的祖先元素
  if (videoItemAncestor) {
    // 添加 'on' 类到找到的元素
    videoItemAncestor.classList.add("on");
  }
}

/**
 * 设置iframe中元素的样式
 *
 * 该函数旨在通过提供的id和样式属性，修改指定iframe文档中元素的样式。它首先检查id是否存在且非空，
 * 然后尝试获取该id对应的元素，并最后设置其指定样式的值。如果操作过程中出现异常，函数将捕获异常但不做处理。
 *
 * @param _this 一个对象，其中包含可能的iframe元素id
 * @param id iframe中元素的id，用于定位元素
 * @param property 要设置的样式属性
 * @param value 要设置的样式属性的值
 */
function divSetStyle(_this, id, property, value) {
  // 检查提供的id是否存在且非空
  if (_this[id] && _this[id] !== "") {
    // 尝试根据id获取iframe中的元素
    let iframeDiv = document.getElementById(_this[id]);
    // 如果元素存在，则设置其样式属性
    if (iframeDiv) {
      iframeDiv.style[property] = value;
    }
  }
}
